import { Subscriber } from "./Subscriber";
import { IWatcher, IVMMain } from "../Interfaces/IMVVM";
import { IDispose } from "../Interfaces/IGameManager";
/**
 * 数据监听
 */
export class WatcherBase implements IWatcher, IDispose {
  value: any; //当前监听值
  vm: IVMMain; //监听模型
  id: number;
  expOrFn: any; //执行函数或 执行参数
  updateCall: any; //监听回调
  subIds: any; //监听依赖编号集合
  getter: Function; //获取参数方法
  isArray: boolean = false;
  watchNode: any; //监听节点
  watchAttrName: any;
  /**
   * 监听器构造函数
   * @param ivm 监听VM
   * @param expOrFns  读取数据方法
   * @param node 监听节点
   * @param attrName 监听属性
   * @param updateCalls 更新
   */
  constructor(ivm, expOrFns, node, attrName, updateCalls) {
    this.vm = ivm;
    this.expOrFn = expOrFns;
    this.updateCall = updateCalls;
    this.watchNode = node;
    this.watchAttrName = attrName;
    this.vm.$pools.push(this); //加入资源池

    if (typeof expOrFns === "function") {
      this.getter = expOrFns;
    } else {
      expOrFns = expOrFns.trim();
      this.getter = this.parseGetter(expOrFns);
    }
  }
  /**
   * 数据更新
   */
  update() {
    this.run();
  }
  /**
   *绑定视图更新数据
   */
  run() {
    console.debug("未实现更新代码！");
  }
  /**
   * 获取数据
   */
  get() {
    if (!this.vm) {
      //数据已清空
      return;
    }
    this.vm.$targetWatcher = this; // 将当前订阅者指向自己
    let value = this.getter.call(this.vm, this.vm); // 触发getter，将自身添加到dep中
    this.vm.$targetWatcher = null; // 添加完成 重置
    return value;
  }
  /**
   * 添加订阅对象
   * @param sub 订阅者
   */
  addSub(sub: Subscriber) {
    if (!this.subIds.hasOwnProperty(sub.id)) {
      sub.add(this);
      this.subIds[sub.id] = sub;
    }
  }
  /**
   * 解析get数据
   * @param exp 执行数据（key,或者 key.name）
   */
  parseGetter(exp) {
    if (/[^\w.$]/.test(exp)) return;
    let exps = exp.split(".");
    // 简易的循环依赖处理
    return function (obj) {
      for (let i = 0, len = exps.length; i < len; i++) {
        if (!obj) return;
        obj = obj[exps[i]];
      }
      return obj;
    };
  }
  dispose(disposing?: boolean) {
    this.run = null;
    this.get = null;
    this.getter = null;
  }
}
